package br.com.ps.bombertournament.game;

import java.util.HashMap;
import java.util.Map;

import br.com.ps.bombertournament.game.util.TextureCache;

import com.badlogic.gdx.Application;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;

/**
 * Control the render of the game, collision engine and music playing.  
 * 
 * @author Rennan Stefan Boni - rennanboni@gmail.com
 */
public class Game implements GameObject {
	
	private Map<Integer, Layer> layers = new HashMap<Integer, Layer>();
	
	private Music music;
	
	private CollisionEngine collisionEngine;
	
	
	/**
	 * Called when the {@link Application} is resumed from a paused state. On Android this happens when the activity gets focus
	 * again. On the desktop this method will never be called.
	 */
	public void resume() {
		
	}

	/**
	 * Called when the {@link Application} is resized. This can happen at any point during a non-paused state but will never happen
	 * before a call to {@link #create()}.
	 * 
	 * @param width the new width in pixels
	 * @param height the new height in pixels
	 */
	public void resize(int width, int height) {
		
	}

	/**
	 * Called when the {@link Application} is paused. An Application is paused before it is destroyed, when a user pressed the Home
	 * button on Android or an incoming call happend. On the desktop this will only be called immediately before {@link #dispose()}
	 * is called.
	 */
	public void pause() {
		
	}
	
	/**
	 * Called when the rendering the scene is necessary 
	 */
	public void render(SpriteBatch spriteBatch) {
		for (Integer layerPriority : layers.keySet()) {
			layers.get(layerPriority).render(spriteBatch);
		}
	}
	
	/**
	 * Search in the layers a object with id
	 * 
	 * @param id The id value are looking for.
	 * @return If found return the object otherwise return null
	 */
	public BaseGameObject findObjectById(String id) {
		BaseGameObject result = null;
		
		for (Layer layer : layers.values()) {
			result = layer.findObjectById(id);
			
			if (result != null) {
				break;
			}
		}
		
		return result;
	}
	
	/**
	 * Called when the {@link Application} is destroyed. Preceded by a call to {@link #pause()}.
	 */
	public void dispose() {
		if (layers != null) {
			for (Layer layer : layers.values()) {
				layer.dispose();
			}
		}
		
		if (music != null) {
			music.dispose();
		}
		
		TextureCache.dispose();
	}

	/**
	 * Called when the update game objects is necessary, and analyse the collision between objects
	 */
	public void update(float deltaTime) {
		for (Integer layerPriority : layers.keySet()) {
			layers.get(layerPriority).update(deltaTime);
		}
		
		if (collisionEngine != null) {
			collisionEngine.collision(layers);
		}
	}

	/**
	 * Return the current music of the scene
	 * 
	 * @return Music of the scene, can be null
	 */
	public Music getMusic() {
		return music;
	}

	/**
	 * Set the new music to the scene
	 * @param music New value to the music's scene
	 */
	public void setMusic(Music music) {
		this.music = music;
	}

	/**
	 * Set the current collision engine
	 * 
	 * @param collisionEngine New value to the collision engine
	 */
	public void setCollisionEngine(CollisionEngine collisionEngine) {
		this.collisionEngine = collisionEngine;
	}

	/**
	 * Add the layer with priority render
	 * 
	 * @param priority Priority of layer
	 * @param layer Layer with game objects
	 * @return
	 */
	public boolean addLayer(Integer priority, Layer layer) {
		boolean result = false;
		
		if (layers != null) {
			layers.put(priority, layer);
		}
		
		return result;
	}
	
	/**
	 * Add the game object into the layer with priority 
	 * 
	 * @param priority Priority necessary to render the object
	 * @param gameObject GameObject that will be rendered
	 * @return Returns true if the layer with priority was founded and does'nt contains the game object, otherwise return false
	 */
	public boolean addGameObject(Integer priority, BaseGameObject gameObject) {
		boolean result = false;
		
		if (layers != null && layers.containsKey(priority)) {
			layers.get(priority).add(gameObject);
		}
		
		return result;
	}
}
